/**
	Pulsar engine.
	Additional include file. File manager. File streams.

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

namespace pl
{

/// Base stream class
class StreamBase
{
public:
	/// Dtor
	virtual ~StreamBase() { }

	/// Check is file succesfully oped for reading or writing
	virtual bool isInited() const = 0;

	/// Get current file size
	virtual pl_int64 getFileSize() const = 0;

	/// Query current file position
	virtual pl_int64 tell() const = 0;

	/// Set new file position
	virtual pl_int64 seek(pl_int64 pos, SeekInfo where) = 0;
};

/**
	Base stream to read data
*/
class StreamRead : public StreamBase
{
public:
	virtual ~StreamRead() {}

	/// Is end of file reached
	virtual bool isEOF() const = 0;

	/// Read block
	virtual bool readBuffer(void* pBuf, pl_int32 itemSize, pl_int32 itemCount, pl_int64* lengthRead = NULL) = 0;

	/// Read POD structure
	template <class T> bool read(T& v)
	{
		return readBuffer(&v, sizeof(T), 1);
	}

	/// Read strings from file
	virtual bool readString(pl_char* pStr, int maxLen, pl_char termChar = PL_T('\0'));

	/// Read strings from file (pl::String version)
	template <pl_uint32 N> bool readString(pl::String<N>& str)
	{
		pl_char buffer[N];
		bool rc = readString(buffer, N, 0);
		if (rc)
		{
			str.set(buffer);
		}
		return rc;
	}

	/// Read strings from file with automatic encoding
	virtual bool readStringEncode(pl_char* pStr, int maxLen, EncodeMode mode, pl_char termChar = PL_T('\0'));

	/// Read strings from file with automatic encoding (pl::String version)
	template <pl_uint32 N> bool readStringEncode(pl::String<N>& str, EncodeMode mode)
	{
		pl_char buffer[N];
		bool rc = readStringEncode(buffer, N, mode, PL_T('\0'));
		if (rc)
		{
			str.set(buffer);
		}
		return rc;
	}

};

/**
	Baset stream to write data
*/
class StreamWrite : public StreamBase
{
public:
	virtual ~StreamWrite() {}

	/// Save data
	virtual bool flush() = 0;

	/// Query maximum align value in seek operation
	virtual int getMaxAlign() const = 0;

	/// Write POD structure with offset
	template <class T> bool writeOffset(T value, pl_int64 offset)
	{
		pl_int64 offsetCur = tell();
		bool rc;

		seek(offset, pl::FILE_SEEK_BEGIN);
		rc = write(value);
		seek(offsetCur, pl::FILE_SEEK_BEGIN);
		return rc;
	}

	/// Set new file size
	virtual bool setFileSize(pl_int64 newSize)
	{
		return false;
	}

	/// Write a block to stream
	virtual bool writeBuffer(const void* pBuf, pl_int32 itemSize, pl_int32 itemCount) = 0;

	/// Write POD structure
	template <class T> bool write(const T& v)
	{
		return writeBuffer(&v, sizeof(T), 1);
	}

	/// Write N zero bytes into stream
	bool writeZero(pl_int64 sizeBytes);

	/// Write a string to file
	bool writeString(const pl_char* pStr, pl_char termChar = PL_T('\0'))
	{
		return writeBuffer(pStr, sizeof(pl_char), pl_strlen(pStr, termChar));
	}

	/// Write a string to file (pl::String version)
	template <pl_uint32 N> bool writeString(const pl::String<N>& str)
	{
		return writeBuffer(str.get(), str.sizeChar(), str.size()+1);
	}

	/// Write a string to file with encoding
	bool writeStringEncode(const pl_char* pStr, EncodeMode mode, pl_char termChar = PL_T('\0'));

	/// Write a string to file with encoding (pl::String version)
	template <pl_uint32 N> bool writeStringEncode(const pl::String<N>& str, EncodeMode mode)
	{
		return writeStringEncode(str.get(), mode, PL_T('\0'));
	}
};

} // namespace pl

//
// End of file 'pulsar_file_stream.h'
//
